/* Javascript blender file renderer
 *
 * Copyright (C) 2010   Nicolas Bonnel (nicolas.bonnel@gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Some parts of this program were inspired from this site : http://learningwebgl.com/blog/
 *
 */

var DEBUG = false;

function info(msg){
	var m = document.createElement("div");
	m.innerHTML = "[INFO] " +msg;
	document.getElementById("console").appendChild(m);
}

function debug(msg){
	if(DEBUG){
		var m = document.createElement("div");
		m.innerHTML = "[DEBUG] " +msg;
		document.getElementById("console").appendChild(m);
	}
}

function warning(msg){
	var m = document.createElement("div");
	m.innerHTML = "[WARNING] " +msg;
	document.getElementById("console").appendChild(m);
}

function error(msg){
	var m = document.createElement("div");
	m.innerHTML = "[ERROR] " +msg;
	document.getElementById("console").appendChild(m);
}

function clearConsole(){
	console = document.getElementById("console");
	while(console.hasChildNodes())
		console.removeChild(console.firstChild);
}

var baseurl;
var reader;
var pointerSize;
var blocs = {};
var stats = [313];
var textures = [];
for (i=0;i<313;i++)
	stats[i]=0;
function parseFile(data,baseur){
	var parsed = new Object();
	info("parsing object ...");
	blocs = {};
	textures = [];
	baseurl=baseur;
	//alert("Parsing file");
	debug("Parsing file");
	reader = new BinaryParser(data[8] == 'V',true);
	if (data[7] == '_')
		pointerSize = 4;
	else
		pointerSize = 8;
		var version = data.substring(9,12);
	debug("File version : "+version+" , pointer size : "+pointerSize);
	var pos = 12
	var code = data.substring(pos,pos+4);
	var prevCode,prevSize,prevPos;
	while (code != 'DNA1' && code != 'ENDB'){
		try{
			var size = reader.toInt(data.substring(pos+4,pos+8));
			var bloc = new Block(code,data.substring(pos+8,pos+size+16+pointerSize));
			if (size>16187392){
				size -= 16187392;
				debug(code+', '+bloc.SDNAindex+' , '+bloc.count +", Bloc size : "+size);
			}
			var bloc = new Block(code,data.substring(pos+8,pos+size+16+pointerSize));
			blocs[bloc.oldMemAdress] = bloc.process();
			prevPos = pos;
			pos += size+16+pointerSize;
			prevCode = code;
			prevSize = size;
			code = data.substring(pos,pos+4);
		}catch(e){
			error( prevCode+' , '+prevSize+' , '+prevPos+' , '+pos+' , '+size+" "+data.substring(prevPos,prevPos+20) );
		}
		
	}
	parsed.objs = [];
	for (var bloc in blocs){
		if(blocs[bloc].SDNAindex==113){	
			var ob = new Obj(blocs[bloc].chunk);	
			debug("Object found : "+ob.oname);
			if(ob.mesh){
				parsed.objs.push(ob);
				debug("Mesh found");
			}
		}
		//blocs[bloc].process();
	}
	//for (i=0;i<313;i++)
		//if(stats[i]>0)
			//debug(i+ ":"+ stats[i]);
	parsed.textures = textures;
	return parsed;
};	



function Block (code,data){
	this.size = data.length-pointerSize-8;
	this.oldMemAdress = data.substring(0,pointerSize);
	this.SDNAindex = reader.toInt(data.substring(pointerSize,pointerSize+4));
	this.count = reader.toInt(data.substring(pointerSize+4,pointerSize+8));
	this.chunk = data.substring(pointerSize+8,pointerSize+this.size+16);
	this.process = function(){
		stats[this.SDNAindex]++;
		switch(this.SDNAindex){
			case 31:debug("ImageUser : "+this.getName());
				return this;
			case 32:debug("Image found : "+this.getName());
				info("Image name : "+this.chunk.substring(4*pointerSize,24+pointerSize*4));
					var nam = this.chunk.substring(32+5*pointerSize,272+pointerSize*5);
					var endPref = nam.lastIndexOf('/');
					if (endPref==-1)
						endPref = nam.lastIndexOf('\\');
					nam = nam.substring(endPref+1,nam.indexOf('\0'));
					nam = baseurl+nam.substring(0,nam.length-3)+"jpg";
					//this.textIndice = textures.length;
					textures.push(nam);
				return nam;
			case 33:debug("MTex found : " +this.getName());
				return this;
			case 36:debug("ColorBand : "+this.getName());
				return this;
			case 37:debug("EnvMap : "+this.getName());
				return this;
			case 38:debug("Tex found : "+this.getName());
				return this;
			case 39:debug("TexMapping : "+this.getName());
				return this;
			case 58:debug("MVert bloc found");
				return this;
			default:
				return this;
		}
		
	};
	this.getName = function(){
		return this.chunk.substring(pointerSize*4,pointerSize*4+24);
	}
};

function MTex(chunk){

}

function Scene(chunk){
	this.sname = chunk.substring(pointerSize*4,pointerSize*4+24);
	this.world = new World(blocs[chunk.substring(32+pointerSize*6,32+pointerSize*7)].chunk);
	debug("Scene : "+this.sname+", world : "+this.world.wname);
	this.camera = blocs[chunk.substring(32+pointerSize*5,32+pointerSize*6)];
	//info("Camera : "+this.camera.getName());
	this.objects = [];
	var base = blocs[chunk.substring(32+pointerSize*9,32+pointerSize*10)];
	while(base){
		var object = new Obj(blocs[base.chunk.substring(16+2*pointerSize,16+3*pointerSize)].chunk);
		this.objects.push(object);
		base = blocs[base.chunk.substring(0,pointerSize)];
	}
};

function World(chunk){
	this.wname = chunk.substring(pointerSize*4,pointerSize*4+24);
};

function Obj(chunk){
	this.oname = chunk.substring(pointerSize*4,pointerSize*4+24);
	debug("Object : "+this.oname);
	this.data = blocs[chunk.substring(80+(16)*pointerSize,80+(17)*pointerSize)];
	//info("Data : "+this.data.SDNAindex);
	this.mesh = null;
	this.shader = null;
	this.textures = [];
	if (this.data.SDNAindex == 52){
		this.mesh = new Mesh(this.data.chunk);
		if (this.mesh.vertices.length<=12)
			this.mesh = null;
	}
}

function Mesh(chunk){
	var verticesBlock = blocs[chunk.substring(32+pointerSize*14,32+pointerSize*15)];
	//debug("vertice bloc code : "+verticesBlock.SDNAindex);
	var facesBlock = blocs[chunk.substring(32+pointerSize*11,32+pointerSize*12)];
	var textBlock = blocs[chunk.substring(32+pointerSize*12,32+pointerSize*13)];
	this.vertices = [];
	this.faces = [];
	this.textures = [];
	this.materials = [];
	this.normals = [];
	this.mname = chunk.substring(pointerSize*4,pointerSize*4+24);
	var ind =0;
	var offset;
	if(verticesBlock && facesBlock)
	for (i=0;i<facesBlock.count;i++){
		try{
			for(j=0;j<3;j++){
				this.faces.push(ind);
				ind++;
				offset = j*4+i*20;
				var vertex = reader.toInt(facesBlock.chunk.substring(offset,4+offset));
				offset = j*8+i*(40+pointerSize);
				if (textBlock){
					this.textures.push(reader.toFloat(textBlock.chunk.substring(offset,4+offset)));
					this.textures.push(reader.toFloat(textBlock.chunk.substring(4+offset,8+offset)));
				}
				//info([textBlock.chunk.substring(32,32+pointerSize)]);
			//	if(tex)
				//	info(tex);
				var norms = [];
				var module = 0;
				for(k=0;k<3;k++){
					offset = k*4+vertex*24;
					this.vertices.push(reader.toFloat(verticesBlock.chunk.substring(offset,4+offset)));
					offset = 12+k*2+vertex*24;
					norms.push(reader.toShort(verticesBlock.chunk.substring(offset,2+offset)));
					if(norms[k]>16000000)
						norms[k]-=16187392;
					module += norms[k]*norms[k];
				}
				module = Math.sqrt(module);
				for(k=0;k<3;k++)
					this.normals.push(norms[k]/module);
			}
			offset = 12+i*20;
			if (facesBlock.chunk.substring(offset,4+offset)!='\0\0\0\0'){
				var vertex = reader.toInt(facesBlock.chunk.substring(offset,4+offset));
				offset = 24+i*(40+pointerSize);
				if (textBlock){
					this.textures.push(reader.toFloat(textBlock.chunk.substring(offset,4+offset)));
					this.textures.push(reader.toFloat(textBlock.chunk.substring(4+offset,8+offset)));
				}
				var norms = [];
				var module = 0;
				for(k=0;k<3;k++){
					offset = k*4+vertex*24;
					this.vertices.push(reader.toFloat(verticesBlock.chunk.substring(offset,4+offset)));
					offset = 12+k*2+vertex*24;
					norms.push(reader.toShort(verticesBlock.chunk.substring(offset,2+offset)));
					if(norms[k]>16000000)
						norms[k]-=16187392;
					module += norms[k]*norms[k];
				}
				module = Math.sqrt(module);
				for(k=0;k<3;k++)
					this.normals.push(norms[k]/module);
				this.faces.push(ind-3);
				this.faces.push(ind-1);	
				this.faces.push(ind);	
				ind+=1;
			}
		}catch(e){
			warning( "facesBlock::missing bytes" );
		}
	}
	info("Mesh detected : "+this.mname+"\nVertices : "+this.vertices.length/3+"\nFaces : "+this.faces.length/3+"\nTextCoord : "+this.textures.length/2);
	//info(this.normals);
	var matBlocks = blocs[chunk.substring(32+pointerSize*10,32+pointerSize*11)];
	if(matBlocks && matBlocks.size>0)
		for (i=0;i<matBlocks.size/pointerSize;i++){
			this.materials.push(new Material(blocs[matBlocks.chunk.substring(pointerSize*i,4+pointerSize*i)].chunk));
		}
	var tmpBlock = blocs[chunk.substring(32+pointerSize*13,32+pointerSize*14)];
	if(tmpBlock)
		info("TFace : "+tmpBlock.getName());
};

function Material(chunk){
	this.mname = chunk.substring(pointerSize*4,pointerSize*4+24);
	info("Material used : "+this.mname);
	//info("uvname : "+chunk.substring(pointerSize*5+252,pointerSize*5+284))
	for(i=7;i<25;i++){
		var mtex = blocs[chunk.substring(pointerSize*i+368,pointerSize*(i+1)+368)];
		if (mtex){
			debug("MTex found");
			var tex = blocs[mtex.chunk.substring(8+pointerSize,8+pointerSize*2)];
			var mapTo = reader.toShort(mtex.chunk.substring(2,4));
			if(tex){
				debug("Tex name : "+tex.chunk.substring(4*pointerSize,24+pointerSize*4));
				var ima = blocs[tex.chunk.substring(216+pointerSize*7,216+pointerSize*8)]
				if(ima){
					if (mapTo%2==1){
						info("Texture found for color : "+ima);
						var index = textures.indexOf(ima);
						var tmp = textures[index];
						textures[index] = textures[0];
						textures[0] = tmp;
						//textures.push(ima);
					}else
						info(ima+" assigned with code "+mapTo);
				}
			}
		}
	}
};

